import { reactive } from "vue";
import { events } from "./events";

export function useBlockDrag(focusData, lastSelectBlock, data) {
  let dragState = {
    startX: 0, // 拖动时的x
    startY: 0, // 拖动时的y
    dragging: false, // 拖动状态 是否正在拖动
  };

  // 辅助线
  let markLine = reactive({
    x: null,
    y: null,
  });
  // 选中时
  const mousedown = (e) => {
    const { width: BWidth, height: BHeight } = lastSelectBlock.value;
    // console.log("BWidth:", BWidth);
    dragState = {
      startX: e.clientX, // x坐标，相对于浏览器
      startY: e.clientY, // y坐标
      // 所有的选中的组件相对于 画布区域 的top left,
      startPos: focusData.value.focus.map(({ top, left }) => ({ top, left })),

      startLeft: lastSelectBlock.value.left, //拖动前left
      startTop: lastSelectBlock.value.top, //拖动前top
      dragging: false,

      // 初始化辅助线
      lines: (() => {
        let lines = { x: [], y: [] };

        const { unfocused } = focusData.value;
        [
          ...unfocused,
          {
            top: 0,
            left: 0,
            width: data.value.container.width,
            height: data.value.container.height,
          },
        ].forEach((block) => {
          const { top: ATop, left: ALeft, width: AWidth, height: AHeight } = block;
          // 横向 当元素拖拽到和A元素的top一致时，要显示辅助线，辅助线的位置是ATop
          lines.y.push({ showTop: ATop, top: ATop }); // 顶对顶
          lines.y.push({ showTop: ATop, top: ATop - BHeight }); //顶对底
          lines.y.push({ showTop: ATop + AHeight / 2, top: ATop + AHeight / 2 - BHeight / 2 }); // 中对中
          lines.y.push({ showTop: ATop + AHeight, top: ATop + AHeight }); // 底对顶
          lines.y.push({ showTop: ATop + AHeight, top: ATop + AHeight - BHeight }); // 底对底
          // 纵向
          lines.x.push({ showLeft: ALeft, left: ALeft }); //左对左
          lines.x.push({ showLeft: ALeft + AWidth, left: ALeft + AWidth }); // 右对左
          lines.x.push({ showLeft: ALeft + AWidth / 2, left: ALeft + AWidth / 2 - BWidth / 2 }); //中对中
          lines.x.push({ showLeft: ALeft + AWidth, left: ALeft + AWidth - BWidth }); // 右对右
          lines.x.push({ showLeft: ALeft, left: ALeft - BWidth }); // 左对右
        });
        // console.log("lines:", lines);
        return lines;
      })(),
    };
    // 绑定事件
    document.addEventListener("mousemove", mousemove);
    document.addEventListener("mouseup", mouseup);
  };
  // 移动
  const mousemove = (e) => {
    // 拿到移动的xy坐标
    let { clientX: moveX, clientY: moveY } = e;

    // 发送拖动开始事件
    if (!dragState.dragging) {
      dragState.dragging = true; // 正在拖动
      events.emit("start"); // 发送开始事件
    }

    // 计算移动组件的top left  x是相对于浏览器， left相对于绘图区
    let left = moveX - dragState.startX + dragState.startLeft;
    let top = moveY - dragState.startY + dragState.startTop;

    // 遍历linex
    let y = null,
      x = null;
    for (let i = 0; i < dragState.lines.y.length; i++) {
      const { top: t, showTop: s } = dragState.lines.y[i]; // 获取每一根线
      if (Math.abs(t - top) < 5) {
        y = s; // 线要显示的位置

        // 吸附
        moveY = dragState.startY - dragState.startTop + t; // 容器距离顶部的距离+目标高度

        break;
      }
    }
    for (let i = 0; i < dragState.lines.x.length; i++) {
      const { left: l, showLeft: s } = dragState.lines.x[i]; // 同上
      if (Math.abs(l - left) < 5) {
        x = s;

        moveX = dragState.startX - dragState.startLeft + l;

        break;
      }
    }

    // 触发渲染
    markLine.x = x;
    markLine.y = y;

    // 计算移动的距离
    let durX = moveX - dragState.startX; // x方向上移动距离
    let durY = moveY - dragState.startY; // y方向上移动距离

    // 遍历所有选中的block，添加到top left上
    focusData.value.focus.forEach((block, index) => {
      block.top = dragState.startPos[index].top + durY;
      block.left = dragState.startPos[index].left + durX;
    });
  };
  // 释放
  const mouseup = (e) => {
    // 清除绑定事件
    document.removeEventListener("mousemove", mousemove);
    document.removeEventListener("mouseup", mouseup);
    // 松开鼠标 清除辅助线
    markLine.x = null;
    markLine.y = null;
    // 发送拖动结束事件
    if (dragState.dragging) {
      dragState.dragging = false;
      events.emit("end"); // 通过拖动结束事件
    }
  };

  return {
    mousedown,
    mouseup,
    mousemove,
    markLine,
  };
}
